package cn.ljserver.project.webOfficeImpl;

import cn.ljserver.project.config.FileSuffixCache;
import cn.ljserver.project.entity.File;
import cn.ljserver.project.entity.User;
import cn.ljserver.project.service.FileService;
import cn.ljserver.project.service.QnFileService;
import cn.ljserver.project.service.UserService;
import cn.ljserver.tool.weboffice.v3.exception.FileNotExist;
import cn.ljserver.tool.weboffice.v3.exception.FileUploadNotComplete;
import cn.ljserver.tool.weboffice.v3.exception.InvalidArgument;
import cn.ljserver.tool.weboffice.v3.model.DigestType;
import cn.ljserver.tool.weboffice.v3.model.FileInfo;
import cn.ljserver.tool.weboffice.v3.model.FileUploadMultiPhase;
import cn.ljserver.tool.weboffice.v3.service.MultiPhaseFileStorageService;
import cn.ljserver.tool.weboffice.v3.util.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * 三阶段文件保存接口（复杂，建议用Single方式）
 * <br>
 * <a href="https://solution.wps.cn/docs/callback/save.html#%E4%B8%89%E9%98%B6%E6%AE%B5%E4%BF%9D%E5%AD%98">详见wps web office官网</a>
 */
@Service
public class MultiPhaseFileStorageServiceImpl implements MultiPhaseFileStorageService {

    @Autowired
    private UserService userService;
    @Autowired
    private FileService fileService;

    /**
     * 准备上传阶段
     *
     * @param s 文件id <br>
     *          <a href = "https://solution.wps.cn/docs/callback/save.html#准备上传阶段">-详见官方文档-</a>
     */
    @Override
    public List<DigestType> uploadPrepare(String s) {
        return Collections.singletonList(DigestType.SHA1);
    }

    /**
     * 获取上传地址
     *
     * @param request 上传的文件 <br>
     *                <a href = "https://solution.wps.cn/docs/callback/save.html#获取上传地址">-详见官方文档-</a>
     */
    @Override
    public FileUploadMultiPhase.FileUploadAddress.Response uploadAddress(FileUploadMultiPhase.FileUploadAddress.Request request) {
        // ATTENTION
        // ConsoleController.upload() handle the upload request
        // and store the new content of file, and create a new version of file
        // without invoke uploadComplete method
        // it is not good in the real world
        // ***************************************************************
        // ***************************************************************
        // 这一步建议将fileName获取到后，拿到文件后缀，然后存到redis，或者其它地方
        // ***************************************************************
        // ***************************************************************
        // 然后在调用 正真的 upload 方法的时候，需要确认当前的文件后缀
        // ***************************************************************
        // ***************************************************************

        // 这里简单的放内存
        String suffix = FileUtils.suffix(request.getName());
        FileSuffixCache.suffixMap.put(request.getFileId(), suffix);

        // 返回地址
        return FileUploadMultiPhase.FileUploadAddress.Response.builder()
                // 方法必须是PUT接口
                .method(FileUploadMultiPhase.FileUploadAddress.Response.Method.PUT)
                // 获取自定义上传接口方法
                // 这里的url是自定义的，需要开发者自己实现,也就是自己的回调地址
                .url(String.format("%s/console/upload/%s", "http://xxx.xxx.cn:4567", request.getFileId()))
                .build();
    }

    /**
     * 上传完成后，回调通知上传结果
     *
     * @param request 上传的文件 <br>
     *                <a href = "https://solution.wps.cn/docs/callback/save.html#上传完成后，回调通知上传结果">-详见官方文档-</a>
     */
    @Override
    public FileInfo uploadComplete(FileUploadMultiPhase.FileUploadComplete.Request request) {
        if (request == null) throw new InvalidArgument();

        // emm
        Optional.of(request)
                .map(FileUploadMultiPhase.FileUploadComplete.Request::getResponse)
                .filter(r -> r.getStatus() == HttpStatus.OK.value())
                .ifPresentOrElse(r -> {
                }, FileUploadNotComplete::new);

        // 获取当前用户,实际不是这么玩的，点进去看看
        User user = userService.fetchUserByToken();

        // 回调中body返回的是url
        // --------------------------------
        // 这里不应该直接URL，而是不带domain的uri方便后续迁移等等
        // 为了方便，就这么弄了
        // --------------------------------
        String url = request.getResponse().getBody();

        // 获取文件 并 返回文件信息
        return Optional.ofNullable(fileService.fetchFile(request.getFileId()))
                .map(f -> File.builder()
                        .id(f.getId().copyForNewVersion())
                        .name(request.getRequest().getName())
                        .size(request.getRequest().getSize())
                        .createTime(f.getCreateTime())
                        .modifyTime(LocalDateTime.now())
                        .creator(f.getCreator())
                        .modifier(user)
                        .url(url)
                        .build())
                .map(f -> fileService.repository().save(f))
                .map(File::toFileInfo)
                .orElseThrow(FileNotExist::new);
    }
}
